package pay.serviceImpl;

import config.ThreadPool;
import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import pay.common.ConstantFYJZH;
import pay.common.ConstantOrderStatus;
import pay.common.ConstantsOrder;
import pay.entity.*;
import pay.portal.web.message.PreAuthMsg;
import pay.portal.web.message.PreAuthResultMsg;
import pay.portal.web.message.ResultMsg;
import pay.service.*;
import pay.service.sys.ISysUser;
import pay.utils.*;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
public class PreAuthCancelImpl implements IPreAuthCancel {

    protected Logger logger = LoggerFactory
            .getLogger(this.getClass().getName());

    /**
     * 商户代码，从配置文件中读取
     */
    @Value("${fy.mchntCd}")
    private String mchnt_cd;

    @Value("${server.scheme}")
    private String serverScheme;

    @Value("${fy.goldAccount.pathBaseUrl}")
    private String pathBaseUrl; // 测试环境为/jzh 生产无。

    @Value("${server.url}")
    private String serverUrl;

    @Value("${fy.withdrawLogFilePath}")
    private String logFilePath;

    /**
     * 金账户baseURl，从配置文件中读取
     */
    @Value("${fy.goldAccount.baseUrl}")
    private String jzhBaseUrl;

    @Autowired
    private ISysUser sysUserService;


    @Autowired
    private ITrade tradeService;

    @Autowired
    private IOrderHelper orderHelperService;

    @Autowired
    private IUserCache userCacheService;



    @Override
    public ResultMsg preAuthCancel(Long orderId) {
        ResultMsg resultMsg = new ResultMsg();

        resultMsg.setResult(false);

        logger.info("进入8082 富友预授权取消接口 orderId ={}",orderId );
        OrderInfo order = null;

        order = orderHelperService.getFromRedis(ConstantsOrder.ORDER_FYJZH_PRIX + orderId);
        if(order == null){
            resultMsg.setRespMsg("订单在redis中不存在， 预授权取消失败！");
            return resultMsg;
        }

        Long userId = order.getUserId();
        SysUser user = sysUserService.findById(userId);

        //客户入账
        String  in_cust_no= order.getCreditorPhoneNum();

        //理财师出账
        String out_cust_no  = user.getName();

        //合同号
        String contract_no = order.getContract_no();

        if(orderId == null|| userId == null || StringHelper.isEmpty(out_cust_no) || StringHelper.isEmpty(in_cust_no) || StringHelper.isEmpty(contract_no)) {
            logger.info("进入8082 富友预授权取消接口 preAuthCancel, 部分参数为空");
            logger.info("preAuthCancel 入参 orderId ={}, out_cust_no={}, in_cust_no={}, contract_no={}", orderId, out_cust_no, in_cust_no, contract_no);
            resultMsg.setRespMsg("部分参数为空， 预授权取消失败！");
            return resultMsg;
        }

        return preAuthCancel(  orderId,  userId, out_cust_no, in_cust_no, contract_no);

    }


    @Override
    public ResultMsg preAuthCancel(PreAuthMsg req) {

        Long orderId = req.getOrderId();
        Long userId = req.getUserId();
        String out_cust_no = req.getOut_cust_no();
        String in_cust_no = req.getIn_cust_no();
        String contract_no = req.getContract_no();

        if(orderId == null|| userId == null || StringHelper.isEmpty(out_cust_no) || StringHelper.isEmpty(in_cust_no) || StringHelper.isEmpty(contract_no)) {
            logger.info("进入8082 富友预授权取消接口 preAuthCancel, 部分参数为空");
            logger.info("preAuthCancel 入参 orderId ={}, out_cust_no={}, in_cust_no={}, contract_no={}", orderId, out_cust_no, in_cust_no, contract_no);
            ResultMsg resultMsg = new ResultMsg();
            resultMsg.setRespMsg("部分参数为空， 预授权取消失败！");
            resultMsg.setResult(false);
            return resultMsg;
        }

        return preAuthCancel(  orderId,  userId, out_cust_no, in_cust_no, contract_no);
    }


    @Override
    public ResultMsg preAuthCancel(Long orderId, Long userId, String out_cust_no, String in_cust_no, String contract_no) {
        logger.info("进入8082 富友预授权取消接口");
        logger.info("PreAuthCancelCtrl 入参 orderId ={}, out_cust_no={}, in_cust_no={}, contract_no={}", orderId, out_cust_no, in_cust_no, contract_no);

        ResultMsg resultMsg = new ResultMsg();
        resultMsg.setAmtBigDecimal(null);
        resultMsg.setContract_no(null);
        resultMsg.setMchnt_txn_ssn(null);
        resultMsg.setRespMsg("");
        resultMsg.setResult(false);

        Boolean result = false;
        OrderInfo order = null;

        order = orderHelperService.getFromRedis(ConstantsOrder.ORDER_FYJZH_PRIX + orderId);

        // 01 .检查订单在redis是否存在
        if (order == null) {
            logger.info("进入富友预授权取消接口， redis中订单数据为空 orderId = {}", orderId);
            resultMsg.setRespMsg("需要取消预授权的订单不存在！");
            resultMsg.setResult(false);

            return resultMsg;
        }

        BigDecimal amt = order.getSuccessAmount();

        // 流水号
        String mchnt_txn_ssn = getSSN(orderId);

        logger.info("进入富友取消预授权接口关键入参mchnt_txn_ssn={},out_cust_no={},in_cust_no={},contract_no={}", mchnt_txn_ssn, out_cust_no, in_cust_no, contract_no);

        // 02 .主要参数检查
        if (StringHelper.isEmpty(mchnt_txn_ssn)
                || StringHelper.isEmpty(out_cust_no)
                || StringHelper.isEmpty(in_cust_no)
                || StringHelper.isEmpty(contract_no)) {
            logger.info("进入富友取消预授权接口，参数检查， 入参有空参数");
            resultMsg.setRespMsg("进入富友取消预授权接口，参数检查， 入参有空参数！");
            resultMsg.setResult(false);
            return resultMsg;
        }


        // 调用富友接口，进行冻结
        RedisCilent.setString(mchnt_txn_ssn, orderId.toString(), 172800);

        String resultStr = sendPostToFY(mchnt_txn_ssn, out_cust_no, in_cust_no, contract_no);

        String resp_code = XmlUtils.getVal(resultStr, "resp_code");


        logger.info("进入富友取消预授权接口， resultStr ={}, resp_code={}, contract_no={}", resultStr, resp_code, contract_no);

        String resp_desc = "";

        if (resp_code.equals("0000")) {
            logger.info("富友取消预授权成功，orderId={}, contract_no={}， resp_code={}", orderId, contract_no, resp_code);
            resp_desc = "富友取消预授权成功";

            try {
                ThreadPool.execute(() -> refundOrderInThread(orderId));
            }catch (Exception ex){
                logger.error("refundOrderInThread Failed ! = {}",ex.getMessage());
                ex.printStackTrace();
            }

            result = true;
        } else if (resultStr.equals(ConstantFYJZH.HTTP_ERROR_RETURN)
                || resp_code.equals("5138")) {
            logger.info("富友取消预授权接口，orderId={}, contract_no={}，resp_code={}", orderId, contract_no, resp_code);
            resp_desc = "失败";
            result = false;
        } else if (resultStr.equals(ConstantFYJZH.HTTP_ERROR_RETURN)
                || resp_code.equals("3122")) {
            logger.info("富友取消预授权接口，原预授权已取消，请勿重复提交， orderId={}, contract_no={}，resp_code={}", orderId, contract_no, resp_code);
            resp_desc = "原预授权已取消，请勿重复提交";
            result = false;
        } else {
            logger.info("富友取消预授权接口，请重试。 orderId={}", orderId);
            resp_desc = "失败";
            result = false;
        }

        //添加到交易记录表中
        addIntoLogFile( mchnt_txn_ssn, out_cust_no, in_cust_no, contract_no, resp_code, resp_desc);

        //添加到tracd表中
        updTradeTable( orderId,  userId,  mchnt_txn_ssn,  contract_no, amt, resp_code,  resp_desc);

        resultMsg.setRespMsg(resp_desc);
        resultMsg.setResult(result);
        resultMsg.setMchnt_txn_ssn(mchnt_txn_ssn);
        resultMsg.setContract_no(contract_no);

        return resultMsg;
    }

    private void refundOrderInThread(Long orderId) {

        try {
            // wait for 10 secs
            logger.info("取消预授权成功 等待5分钟再进行订单退款处理");
            Thread.sleep(300000);

            //订单退款处理
            Boolean refundResult = orderHelperService.refundOrder(orderId);
            logger.info("取消预授权成功 进行订单退款处理 refundResult={}", refundResult);

        } catch (InterruptedException e) {
            logger.error("退款处理失败 ",e.getMessage());
            e.printStackTrace();
        }

    }


    public String sendPostToFY(String mchnt_txn_ssn, String out_cust_no, String in_cust_no, String contract_no) {
        String rem = "";
        String pathUrl = pathBaseUrl + "/preAuthCancel.action";
        URIBuilder builder = new URIBuilder().setScheme("https")
                .setHost(jzhBaseUrl).setPath(pathUrl);
        logger.info(builder.toString());
        Map<String, String> trimmedParams = new HashMap<>();

        String allUrl = contract_no + "|" + in_cust_no + "|" + mchnt_cd + "|"
                + mchnt_txn_ssn + "|" + out_cust_no + "|" + rem;

        SecurityUtils.initPrivateKey();
        SecurityUtils.initPublicKey();
        String signature = SecurityUtils.sign(allUrl);

        trimmedParams.put("mchnt_txn_ssn", mchnt_txn_ssn);
        trimmedParams.put("out_cust_no", out_cust_no);
        trimmedParams.put("in_cust_no", in_cust_no);
        trimmedParams.put("contract_no", contract_no);
        trimmedParams.put("rem", rem);
        trimmedParams.put("signature", signature);
        trimmedParams.put("mchnt_cd", mchnt_cd);
        String openResult = FYApiUtil.doPost(builder, trimmedParams);
        logger.info("进入8082 富友预授权取消接口， will send msg to FY,  openResult={}", openResult);
        return openResult;
    }

    //将预授权取消记录写入日志文件
    public Boolean addIntoLogFile(  String mchnt_txn_ssn, String out_cust_no, String in_cust_no, String contract_no, String resp_code, String resp_desc){
        try {
            String logRecord = DateUtil.transferLongToDate(
                    "yyyy-MM-dd HH:mm:ss", System.currentTimeMillis())
                    + "----富友取消预授权接口: "
                    + " mchnt_txn_ssn = " + mchnt_txn_ssn
                    + ",out_cust_no = " + out_cust_no
                    + ",in_cust_no = " + in_cust_no
                    + ",resultCode="  + resp_code
                    + ",resp_desc=" + resp_desc
                    + "\r\n";
            logger.info("富友取消预授权接口 = " + logRecord);
            writeFile(logRecord);

        } catch (Exception e) {
            logger.error("写绑卡文本文件失败！", e);
        }
        return true;
    }

    /**
     * 写日志文件
     * @param record
     */
    public void writeFile(String record) {
        Long cts = System.currentTimeMillis();
        String pathName = "preAuthCancelLogRecords-"
                + DateUtil.transferLongToDate("yyyyMM", cts) + ".txt";

        Path filePath = Paths.get(logFilePath + pathName);

        if (!Files.exists(filePath)) {
            try {
                StringBuilder fileStr = new StringBuilder();
                fileStr.append("0 | | 1\r\n").append(
                        "序号|创建时间|请求流水号|出账账户|入账账户|响应码|描述信息|\r\n");
                fileStr.append(record);

                Files.write(filePath, fileStr.toString().getBytes("UTF-8"));
            } catch (IOException e) {
                logger.error("首次写文件失败！", e);
            }
        } else {// 存在则追加
            try {
                Files.write(filePath, record.getBytes("UTF-8"),
                        StandardOpenOption.APPEND);
            } catch (IOException e) {
                logger.error("追加写文件失败！", e);
            }

        }

    }
    //获取流水号
    private String getSSN(Long orderId) {

        String ctsLong = String.valueOf(System.currentTimeMillis());

        String cts = ctsLong.substring(ctsLong.length() - 4, ctsLong.length());

        //生成流水号
        String mchnt_txn_ssn = cts + orderId + ConstantFYJZH.MSSN_YSQ_QUXIAO;

        return mchnt_txn_ssn;
    }

    //更新trade表
    public void updTradeTable(Long orderId, Long userId,String mchnt_txn_ssn, String contract_no, BigDecimal amt, String resp_code, String resp_desc) {

        Trade trade = new Trade();
        trade.setUserId(userId);
        trade.setType(ConstantFYJZH.TRADE_TY_YSQ_CANCEL);
        trade.setFlowType(ConstantFYJZH.BALANCE_CUT);
        trade.setMchnt_txn_ssn(mchnt_txn_ssn);
        trade.setLogin_id(userId.toString());
        trade.setOrderId(orderId);
        trade.setCts(System.currentTimeMillis());
        trade.setTradeDesc("取消预授权");
        trade.setResp_code(resp_code);
        trade.setContract_no(contract_no);
        trade.setAmt(amt);
        tradeService.save(trade);

        tradeService.hiddenRecordByContractNo(contract_no);
    }

}